﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using FrameConstructor;


namespace TetrisShape
{
    public class Field
    {
        public static int scoreCounter = 0;
        public static Block[] element = new Block[200];
        private int RemoveLine = 0;
        MainMenu mm = new MainMenu();
        private bool flag = true;
        private List<Shape> fieldShapeStorage = new List<Shape>();
        public List<Shape> returnFieldShapeStorage { get { return fieldShapeStorage; } }

        private InputHandler _userInputHandler;

        Render rd = new Render();
        Frame fr = new Frame();
        Block bl = new Block();
        Shape globalShape = new Shape();

        public Field(InputHandler inputHandler)
        {
            _userInputHandler = inputHandler;
        }
        //Set field for game
        public Frame SetGameField()
        {
            if (fieldShapeStorage.Count == 0)
            {
                Console.Clear();
            }
            Console.ForegroundColor = ConsoleColor.White;
            fr.SetFrame(20, 20, 31, 41);
            return fr;
        }
        //Shape is doing step
        public void Move()
        {
            Shape sh = new Shape();
            ChangeSpeed();
            globalShape = sh;
            sh.CreateRandomShape(SetGameField(), sh);
            do
            {
                _userInputHandler.QueryKeyBoard();
                rd.Print(sh, fr, MainMenu.globalF);
                scoreCounter = 0;
                bl.DoStep(sh);
            } while (IsPositionFree(sh));

            fieldShapeStorage.Add(sh);
        }
        //Shape is doing step while it doesn't find end of field or another shape
        public void StartMoveShape()
        {
            _userInputHandler.MoveLeft += _userInputHandler_GoMoveLeft;
            _userInputHandler.MoveRight += _userInputHandler_GoMoveRight;
            _userInputHandler.SpeedUp += _userInputHandler_GoSpeedUp;
            _userInputHandler.Rotate += _userInputHandler_GoRotate;

            do
            {
                Move();
                while (GetLineForRemove(fr))
                {
                    globalShape.RemoveBlock(element, MainMenu.globalF, RemoveLine);
                    scoreCounter += 1;
                } 
            } while (flag);
            Console.Clear();
            Console.SetCursorPosition(fr.StartX + 2, fr.StartY + 10);
            Console.BackgroundColor = ConsoleColor.White;
            Console.ForegroundColor = ConsoleColor.Black;
            Console.WriteLine("GAME OVER");
            Console.ReadLine();
        }

        void _userInputHandler_GoMoveRight(object sender, EventArgs e)
        {
            bl.BlockMoveRight(globalShape, fr);
        }

        void _userInputHandler_GoMoveLeft(object sender, EventArgs e)
        {
            bl.BlockMoveLeft(globalShape, fr);
        }

        void _userInputHandler_GoSpeedUp(object sender, EventArgs e)
        {
            Block.Speed = 0;
        }
        //Rotate shape
        void _userInputHandler_GoRotate(object sender, EventArgs e)
        {
            switch (globalShape.ShapeType)
            {
                case "Line": globalShape.RotateLine(); break;
                case "T": globalShape.RotateT(); break;
                case "ZigZag": globalShape.RotateZigZag(); break;
                case "ZigZagReverse": globalShape.RotateZigZagReverse(); break;
                case "G": globalShape.RotateG(); break;
                case "GReverse": globalShape.RotateGReverse(); break;
                default: break;
            }
        }
        //Defines whether shape do step in next position
        public bool IsPositionFree(Shape sh)
        {
            if (fieldShapeStorage.Count != 0)
            {
                foreach (Shape currentShape in sh.returnShape)
                {
                    foreach (Block currentBlock in sh.returnBlock)
                    {
                        foreach (Shape shapeInStorage in fieldShapeStorage)
                        {
                            foreach (Block blockInStorage in shapeInStorage.returnBlock)
                            {
                                if ((currentBlock.X == blockInStorage.X && currentBlock.Y == blockInStorage.Y - 1) || currentBlock.Y == fr.StartY + 20)
                                {
                                    if (currentBlock.Y <= fr.StartY + 5)
                                    {
                                        foreach (Block curBlock in sh.returnBlock)
                                            if (curBlock.Y == fr.StartY + 2)
                                            {
                                                flag = false;
                                                return false;
                                            }
                                    }
                                    return false;
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                foreach (Shape shape in sh.returnShape)
                {
                    foreach (Block block in sh.returnBlock)
                    {
                        if (block.Y == fr.StartY + 20)
                            return false;
                    }
                }
            }
            return true;
        }
        //Get line which we can delete
        public bool GetLineForRemove(Frame fr)
        {
            int i = 0;
            int k = 0;

            for (int z = 20; z > 0; z--)
            {
                foreach (Shape sh in fieldShapeStorage)
                {
                    foreach (Block bl in sh.returnBlock)
                    {
                        if (bl.Y == fr.StartY + z)
                        {
                            element[k] = bl;
                            i += 1;
                            k++;
                        }
                    }

                    if (i / 10 == 1)
                    {
                        RemoveLine = fr.StartY + z;
                        return true;
                    }
                }
                i = 0;
            }
            return false;
        }
        //Change game speed when we have quantity of points needed for this
        public void ChangeSpeed()
        {
            if (rd.TotalScore < 500)
                Block.Speed = 500;
            else if (rd.TotalScore < 1000)
                Block.Speed = 400;
            else if (rd.TotalScore < 1500)
                Block.Speed = 300;
            else if (rd.TotalScore < 2000)
                Block.Speed = 200;
            else if (rd.TotalScore < 2500)
                Block.Speed = 100;
        }
    }
}
